﻿namespace PerpetuumSoft.InstrumentationPDA
{
    using PerpetuumSoft.InstrumentationPDA.Mathematics;
    using System;
    using System.Drawing;
    using System.Runtime.CompilerServices;
    using System.Windows.Forms;

    public abstract class ValuePresenter : Widget
    {
        private bool dragging;
        private string format = "0.##";
        private bool isIndicatorOnly;
        private decimal maximum = 100M;
        private decimal minimum;
        private decimal step;
        private decimal value;

        public event EventHandler ValueChanged;

        protected ValuePresenter()
        {
        }

        protected string FormatValue(decimal value)
        {
            return value.ToString(this.format);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if ((!this.isIndicatorOnly && base.Enabled) && (e.Button == MouseButtons.Left))
            {
                base.Capture = true;
                this.dragging = true;
                this.Value = this.ToValue(new Point(e.X, e.Y));
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (!this.isIndicatorOnly && this.dragging)
            {
                this.Value = this.ToValue(new Point(e.X, e.Y));
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if ((!this.isIndicatorOnly && this.dragging) && (e.Button == MouseButtons.Left))
            {
                base.Capture = false;
                this.dragging = false;
            }
        }

        protected virtual void OnValueChanged(EventArgs e)
        {
            if (this.ValueChanged != null)
            {
                this.ValueChanged(this, e);
            }
        }

        protected decimal PercentToValue(decimal value)
        {
            return (this.Minimum + (value * (this.Maximum - this.Minimum)));
        }

        protected abstract Vector ToPoint(decimal value);
        protected abstract decimal ToValue(Vector v);
        protected decimal ValueToPercent(decimal value)
        {
            return ((value - this.Minimum) / (this.Maximum - this.Minimum));
        }

        public string Format
        {
            get
            {
                return this.format;
            }
            set
            {
                if (this.format != value)
                {
                    this.format = value;
                    base.InvalidateStatic();
                }
            }
        }

        public bool IsIndicatorOnly
        {
            get
            {
                return this.isIndicatorOnly;
            }
            set
            {
                this.isIndicatorOnly = value;
            }
        }

        public decimal Maximum
        {
            get
            {
                return this.maximum;
            }
            set
            {
                if (this.maximum != value)
                {
                    this.maximum = value;
                    base.InvalidateStatic();
                }
            }
        }

        public decimal Minimum
        {
            get
            {
                return this.minimum;
            }
            set
            {
                if (this.minimum != value)
                {
                    this.minimum = value;
                    base.InvalidateStatic();
                }
            }
        }

        public decimal Step
        {
            get
            {
                return this.step;
            }
            set
            {
                if ((this.step != value) && (value >= 0M))
                {
                    this.step = value;
                    base.Invalidate();
                }
            }
        }

        public decimal Value
        {
            get
            {
                return this.value;
            }
            set
            {
                if (value > this.maximum)
                {
                    value = this.maximum;
                }
                if (value < this.minimum)
                {
                    value = this.minimum;
                }
                if (value != this.value)
                {
                    if (this.step != 0M)
                    {
                        this.value = base.Round(value / this.step) * this.step;
                    }
                    else
                    {
                        this.value = value;
                    }
                    this.OnValueChanged(EventArgs.Empty);
                    base.Invalidate();
                }
            }
        }
    }
}

